package project12;

import java.util.*;

/**
 * 习题类，用于管理一组算式练习题
 */
class Exercise {
    // 成员变量
    private List<ArithmeticProblem> problems;  // 存储算式列表
    private int totalProblems;                 // 总题数
    private int additionCount;                 // 加法题数量
    private int subtractionCount;              // 减法题数量

    // 构造函数
    public Exercise(int totalProblems) {
        this.totalProblems = totalProblems;
        this.problems = new ArrayList<>();
        this.additionCount = 0;
        this.subtractionCount = 0;
    }

    // 生成练习题
    public void generateProblems() {
        Random random = new Random();
        Set<String> generatedKeys = new HashSet<>();
        problems.clear();
        additionCount = 0;
        subtractionCount = 0;

        // 确保至少有一定数量的加法和减法题
        while (additionCount < 5 && problems.size() < totalProblems) {
            int num1 = random.nextInt(101);
            int num2 = random.nextInt(101 - num1);
            String key = num1 + "+" + num2;

            if (!generatedKeys.contains(key)) {
                problems.add(new ArithmeticProblem(num1, num2, '+'));
                generatedKeys.add(key);
                additionCount++;
            }
        }

        while (subtractionCount < 5 && problems.size() < totalProblems) {
            int num1 = random.nextInt(101);
            int num2 = random.nextInt(num1 + 1);
            String key = num1 + "-" + num2;

            if (!generatedKeys.contains(key)) {
                problems.add(new ArithmeticProblem(num1, num2, '-'));
                generatedKeys.add(key);
                subtractionCount++;
            }
        }

        // 继续生成直到达到指定数量
        while (problems.size() < totalProblems) {
            int operation = random.nextInt(2);

            if (operation == 0) { // 加法
                int num1 = random.nextInt(101);
                int num2 = random.nextInt(101 - num1);
                String key = num1 + "+" + num2;

                if (!generatedKeys.contains(key)) {
                    problems.add(new ArithmeticProblem(num1, num2, '+'));
                    generatedKeys.add(key);
                    additionCount++;
                }
            } else { // 减法
                int num1 = random.nextInt(101);
                int num2 = random.nextInt(num1 + 1);
                String key = num1 + "-" + num2;

                if (!generatedKeys.contains(key)) {
                    problems.add(new ArithmeticProblem(num1, num2, '-'));
                    generatedKeys.add(key);
                    subtractionCount++;
                }
            }
        }
    }

    // 显示题目（不含答案）
    public void displayProblems() {
        System.out.println("题目:");
        for (int i = 0; i < problems.size(); i += 5) {
            for (int j = 0; j < 5 && (i+j) < problems.size(); j++) {
                System.out.print(String.format("%-15s", problems.get(i+j).toProblemString()));
            }
            System.out.println();
        }
    }

    // 显示题目和答案
    public void displayProblemsWithAnswers() {
        System.out.println("题目和答案:");
        for (int i = 0; i < problems.size(); i += 5) {
            for (int j = 0; j < 5 && (i+j) < problems.size(); j++) {
                System.out.print(String.format("%-20s", problems.get(i+j).toString()));
            }
            System.out.println();
        }
    }

    // 检查是否有重复题目
    public boolean hasDuplicateProblems() {
        Set<String> keys = new HashSet<>();
        for (ArithmeticProblem problem : problems) {
            String key = problem.getKey();
            if (keys.contains(key)) {
                return true;
            }
            keys.add(key);
        }
        return false;
    }

    // Getter方法
    public List<ArithmeticProblem> getProblems() {
        return new ArrayList<>(problems); // 返回副本以保护内部数据
    }

    public int getTotalProblems() {
        return totalProblems;
    }

    public int getAdditionCount() {
        return additionCount;
    }

    public int getSubtractionCount() {
        return subtractionCount;
    }

    // 获取统计信息
    public String getStatistics() {
        return String.format("总题数: %d, 加法题: %d, 减法题: %d",
                totalProblems, additionCount, subtractionCount);
    }
}

/**
 * 算术问题类
 */
class ArithmeticProblem {
    private int operand1;
    private int operand2;
    private char operator;
    private int result;

    // 构造函数
    public ArithmeticProblem(int operand1, int operand2, char operator) {
        this.operand1 = operand1;
        this.operand2 = operand2;
        this.operator = operator;
        // 计算结果
        if (operator == '+') {
            this.result = operand1 + operand2;
        } else {
            this.result = operand1 - operand2;
        }
    }

    // 重写toString方法，方便输出（包括答案）
    @Override
    public String toString() {
        return String.format("%2d %c %2d = %3d", operand1, operator, operand2, result);
    }

    // 不带答案的字符串表示
    public String toProblemString() {
        return String.format("%2d %c %2d =   ", operand1, operator, operand2);
    }

    // 重写equals和hashCode方法以支持去重
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        ArithmeticProblem that = (ArithmeticProblem) obj;
        return operand1 == that.operand1 &&
                operand2 == that.operand2 &&
                operator == that.operator;
    }

    @Override
    public int hashCode() {
        return Objects.hash(operand1, operand2, operator);
    }

    // 获取唯一标识符用于比较
    public String getKey() {
        return operand1 + "" + operator + "" + operand2;
    }

    // Getter方法
    public int getOperand1() {
        return operand1;
    }

    public int getOperand2() {
        return operand2;
    }

    public char getOperator() {
        return operator;
    }

    public int getResult() {
        return result;
    }
}

/**
 * 习题类的测试主类
 */
public class ExerciseTest {
    public static void main(String[] args) {
        System.out.println("开始对Exercise类进行单元测试...\n");

        // 测试计数器
        int passedTests = 0;
        int totalTests = 0;

        // 测试1: 习题类构造
        totalTests++;
        if (testExerciseConstruction()) {
            passedTests++;
            System.out.println("✓ 测试1通过: 习题类构造正确");
        } else {
            System.out.println("✗ 测试1失败: 习题类构造错误");
        }

        // 测试2: 生成习题
        totalTests++;
        if (testGenerateProblems()) {
            passedTests++;
            System.out.println("✓ 测试2通过: 生成习题功能正确");
        } else {
            System.out.println("✗ 测试2失败: 生成习题功能错误");
        }

        // 测试3: 习题数量
        totalTests++;
        if (testProblemCount()) {
            passedTests++;
            System.out.println("✓ 测试3通过: 习题数量正确");
        } else {
            System.out.println("✗ 测试3失败: 习题数量错误");
        }

        // 测试4: 加法和减法分布
        totalTests++;
        if (testOperationDistribution()) {
            passedTests++;
            System.out.println("✓ 测试4通过: 运算符分布正确");
        } else {
            System.out.println("✗ 测试4失败: 运算符分布错误");
        }

        // 测试5: 无重复题目
        totalTests++;
        if (testNoDuplicates()) {
            passedTests++;
            System.out.println("✓ 测试5通过: 无重复题目");
        } else {
            System.out.println("✗ 测试5失败: 存在重复题目");
        }

        // 测试6: 统计信息
        totalTests++;
        if (testStatistics()) {
            passedTests++;
            System.out.println("✓ 测试6通过: 统计信息正确");
        } else {
            System.out.println("✗ 测试6失败: 统计信息错误");
        }

        // 输出测试结果总结
        System.out.println("\n==================== 测试结果 ====================");
        System.out.println("总测试数: " + totalTests);
        System.out.println("通过测试: " + passedTests);
        System.out.println("失败测试: " + (totalTests - passedTests));
        System.out.println("通过率: " + String.format("%.2f", (passedTests * 100.0 / totalTests)) + "%");

        if (passedTests == totalTests) {
            System.out.println("🎉 所有测试通过!");
        } else {
            System.out.println("❌ 部分测试未通过，请检查代码。");
        }
    }

    // 测试习题类构造
    private static boolean testExerciseConstruction() {
        try {
            Exercise exercise = new Exercise(10);
            return exercise.getTotalProblems() == 10;
        } catch (Exception e) {
            return false;
        }
    }

    // 测试生成习题
    private static boolean testGenerateProblems() {
        try {
            Exercise exercise = new Exercise(20);
            exercise.generateProblems();
            return exercise.getProblems().size() == 20;
        } catch (Exception e) {
            return false;
        }
    }

    // 测试习题数量
    private static boolean testProblemCount() {
        try {
            Exercise exercise = new Exercise(30);
            exercise.generateProblems();
            return exercise.getProblems().size() == 30;
        } catch (Exception e) {
            return false;
        }
    }

    // 测试加法和减法分布
    private static boolean testOperationDistribution() {
        try {
            Exercise exercise = new Exercise(50);
            exercise.generateProblems();
            // 检查是否同时包含加法和减法
            return exercise.getAdditionCount() > 0 && exercise.getSubtractionCount() > 0;
        } catch (Exception e) {
            return false;
        }
    }

    // 测试无重复题目
    private static boolean testNoDuplicates() {
        try {
            Exercise exercise = new Exercise(40);
            exercise.generateProblems();
            return !exercise.hasDuplicateProblems();
        } catch (Exception e) {
            return false;
        }
    }

    // 测试统计信息
    private static boolean testStatistics() {
        try {
            Exercise exercise = new Exercise(25);
            exercise.generateProblems();
            String stats = exercise.getStatistics();
            return stats.contains("总题数: 25");
        } catch (Exception e) {
            return false;
        }
    }
}
